200. 岛屿数量

Title

Similar Question

Solution Tips

方案一: 构造图 + DFS

var numIslands = function(grid) {
    // 第一次遍历先构建图
    const graph = new Graph();

    // 永远取左边和上边做构建边, 所以可以直接从 1,1 开始遍历
    // 可以增加一个前导0行, 这样保证第一行的节点都可以正确初始化
    grid.unshift(Array.from({ length: grid[0].length }, () => "0"));
    for (let i = 1; i < grid.length; i++) {
        const row = grid[i];
        for (let j = 0; j < row.length; j++) {
            if (grid[i][j] === "1" ) {
                const vertex = [i, j].join(',');
                graph.addVertex(vertex)
                if (grid[i - 1][j] === "1") {
                    graph.addEdge([i - 1, j].join(','), vertex)
                }
                if (grid[i][j - 1] === "1") {
                    graph.addEdge([i, j - 1].join(','), vertex)
                }
            }
        }
    }

    // 然后再次遍历图, 每次队列清空了就是一个单独的岛
    // bfs
    const map = graph.adjList;
    const queue = [];
    let count = 0;
        for (const [key, val] of map) {
        if (queue.length === 0) {
            if (val) {
                queue.push([key, val]);
                count++;
            }
        }

        while (queue.length) {
            // 这个 shift 实在是太慢了, bfs 超时...
            const [vertex, adjList] = queue.shift();

            for (let i = 0; i < adjList.length; i++) {
                map.get(adjList[i]) && queue.push([adjList[i], map.get(adjList[i])]);
            }
            // 处理完该节点后, 置空
            map.set(vertex, null)
        }
    }

    return count;
    // 如果是 dfs
};

方案二: 直接基于网格进行遍历

Dfs

var numIslands = function(grid) {
    // 增加填充行, 参考的是 dummyHead 的逻辑
    const startRow = Array.from({length: grid[0].length}, () => '0');
    const endRow = Array.from({length: grid[0].length}, () => '0');
    grid.unshift(startRow);
    grid.push(endRow);

    let count = 0;
    // 直接从第一行开始遍历即可
    for (let i = 1; i < grid.length; i++) {
        for (let j = 0; j < grid[0].length; j++) {
            if (grid[i][j] === '1') {
                count++;
                dfs(i, j);
            }
        }
    }

    function dfs(r, c) {
        // if (!inArea(grid, r, c)) return;
        if (grid[r][c] !== '1') return;

        // 已经遍历过的岛屿标记为 2
        grid[r][c] = '2';

        // 继续递归四个方向
        dfs(r - 1, c);
        dfs(r + 1, c);
        dfs(r, c + 1);
        dfs(r, c - 1);
    }

    return count;
};

Bfs

var numIslands = function(grid) {
    // 增加填充行, 参考的是 dummyHead 的逻辑
    const startRow = Array.from({length: grid[0].length}, () => '0');
    const endRow = Array.from({length: grid[0].length}, () => '0');
    grid.unshift(startRow);
    grid.push(endRow);

    let count = 0;
    // 直接从第一行开始遍历即可
    for (let i = 1; i < grid.length; i++) {
        for (let j = 0; j < grid[0].length; j++) {
            if (grid[i][j] === '1') {
                count++;
                bfs(i, j);
            }
        }
    }

    function bfs(r, c) {
        // bfs 逻辑也是和二叉树类似的 queue
        const queue = [[r, c]];

        while (queue.length) {
            const vertex = queue.shift();
            const [r, c] = vertex;

            if (grid[r][c] === '1') {
                // 标记已经遍历过, 避免重复
                grid[r][c] = '2';
                // 继续遍历四个方向
                queue.push([r + 1, c]);
                queue.push([r - 1, c]);
                queue.push([r, c + 1]);
                queue.push([r, c - 1]);

            }
        }
    }

    return count;
};

方案三: 并查集